package repositories

import (
	"context"
	"github.com/pkg/errors"
	"go.didapinche.com/foundation/plat-echo/app/ops/models"
	"go.didapinche.com/time"
	"gorm.io/gorm"
	"strconv"
)

type TemplateRepository interface {
	Create(ctx context.Context, t *models.Template) error
	Delete(ctx context.Context, id uint64) error
	Find(ctx context.Context, name string, typeID, kind uint64, pageSize, pageNum int) ([]*models.Template, int64, error) //通过模版分类id和类型查询
	FindByID(ctx context.Context, id uint64) (*models.Template, error)
	FindByNameAndKind(ctx context.Context, name string, kind int) (*models.Template, error)
	Update(ctx context.Context, t *models.Template) error
	FindAlertAll(ctx context.Context, kind int) ([]*models.Template, error) //获得所有模版
	FindSla(ctx context.Context) ([]*models.Template, error)
	FindByIsSla(ctx context.Context) ([]*models.Template, error)
	FindUpdateApp(ctx context.Context, id uint64, name string, pageNum, pageSize int, eq bool) ([]*models.Application, int64, error)   //查询被覆盖或者没有被覆盖对app模版
	FindUpdateApi(ctx context.Context, id uint64, name string, pageNum, pageSize int, eq bool) ([]*models.Api, int64, error)           //查询被覆盖或者没有被覆盖对app模版
	FindUpdateHost(ctx context.Context, id uint64, name string, pageNum, pageSize int, eq bool) ([]*models.HostResource, int64, error) //查询被覆盖或者没有被覆盖对app模版
	FindUpdateHosts(ctx context.Context, id uint64, eq bool) ([]*models.HostResource, int64, error)
	FindUpdateApis(ctx context.Context, id uint64, eq bool) ([]*models.Api, int64, error)
	FindUpdateApps(ctx context.Context, id uint64, eq bool) ([]*models.Application, int64, error)
}

type templateRepository struct {
	db *gorm.DB
}

func NewTemplateRepository(db *gorm.DB) TemplateRepository {
	return &templateRepository{
		db: db,
	}
}

func (r templateRepository) Create(ctx context.Context, t *models.Template) error {
	t.CreateTime = time.Now()
	t.UpdateTime = time.Now()
	if err := r.db.WithContext(ctx).Table(models.TemplateTableName).Create(t).Error; err != nil {
		return errors.Wrap(err, "templateRepository.create error")
	}
	return nil
}

//
func (r templateRepository) Update(ctx context.Context, t *models.Template) error {
	t.UpdateTime = time.Now()
	t.CreateTime = time.Now()
	if err := r.db.WithContext(ctx).Table(models.TemplateTableName).Save(t).Error; err != nil {
		return errors.Wrap(err, "templateRepository.Save error")
	}
	return nil
}

func (r templateRepository) Delete(ctx context.Context, id uint64) error {
	if err := r.db.WithContext(ctx).Table(models.TemplateTableName).Delete(&models.Template{}, id).Error; err != nil {
		return errors.Wrap(err, "templateRepository.Delete error")
	}
	return nil
}

//查询指定ID的模版
func (r templateRepository) FindByID(ctx context.Context, id uint64) (*models.Template, error) {
	template := new(models.Template)
	if err := r.db.WithContext(ctx).Table(models.TemplateTableName).First(template, "id=?", id).Error; err != nil {
		return template, errors.Wrap(err, "templateRepository.FindByID error")
	}
	return template, nil
}

func (r templateRepository) FindByNameAndKind(ctx context.Context, name string, kind int) (*models.Template, error) {
	template := new(models.Template)
	if err := r.db.WithContext(ctx).Table(models.TemplateTableName).First(template, "name=? and kind=?", name, kind).Error; err != nil {
		return template, errors.Wrap(err, "templateRepository.FindByID error")
	}
	return template, nil
}

//获得所有订阅kind,0:app;1:api;2:host;3dashboard
func (r templateRepository) FindAlertAll(ctx context.Context, kind int) ([]*models.Template, error) {
	templates := make([]*models.Template, 0)
	if err := r.db.WithContext(ctx).Table(models.TemplateTableName).Find(&templates, "kind=?", kind).Error; err != nil {
		return nil, errors.Wrap(err, "templateRepository.FindAlertAll error")
	}
	return templates, nil
}

func (r templateRepository) Find(ctx context.Context, name string, typeID, kind uint64, pageSize, pageNum int) ([]*models.Template, int64, error) {
	var count int64
	templates := make([]*models.Template, 0)
	query := ""
	if typeID != 0 {
		query += " and type_id=" + strconv.Itoa(int(typeID))
	}
	if err := r.db.WithContext(ctx).Table(models.TemplateTableName).Where("kind=?  and name like ?"+query, kind, "%"+name+"%").Count(&count).Limit(pageSize).Offset(pageSize * (pageNum - 1)).Order("`order` desc").Scan(&templates).Error; err != nil {
		return nil, 0, errors.Wrap(err, "templateRepository.Find error")
	}
	return templates, count, nil
}

func (r templateRepository) FindSla(ctx context.Context) ([]*models.Template, error) {
	templates := make([]*models.Template, 0)
	if err := r.db.WithContext(ctx).Table(models.TemplateTableName).Find(&templates).Error; err != nil {
		return nil, errors.Wrap(err, "templateRepository.FindSla error")
	}
	return templates, nil
}
func (r templateRepository) FindByIsSla(ctx context.Context) ([]*models.Template, error) {
	templates := make([]*models.Template, 0)
	if err := r.db.WithContext(ctx).Table(models.TemplateTableName).Find(&templates, "sla=1").Error; err != nil {
		return nil, errors.Wrap(err, "templateRepository.FindSla error")
	}
	return templates, nil
}

func (r templateRepository) FindUpdateApp(ctx context.Context, id uint64, name string, pageNum, pageSize int, eq bool) ([]*models.Application, int64, error) {
	var count int64
	apps := make([]*models.Application, 0)
	db := r.db.Begin()
	query := ""
	if id != 0 {
		query = " and t_graph.template_id=" + strconv.Itoa(int(id))
	}
	if !eq {
		err := db.Begin().WithContext(ctx).Raw("select sql_calc_found_rows * from t_app join t_graph on  t_graph.kind=0 "+query+" and t_graph.app_id=t_app.id and t_app.name like ? limit ?,?", "%"+name+"%", (pageNum-1)*pageSize, pageSize).Scan(&apps).Error
		if err != nil {
			return nil, 0, errors.Wrap(err, "templateRepository.FindUpdateApp error")
		}
		err = db.WithContext(ctx).Raw("SELECT FOUND_ROWS() count").Scan(&count).Error
		if err != nil {
			return nil, 0, errors.Wrap(err, "templateRepository.FindUpdateApp error")
		}
		db.Commit()
		return apps, count, nil
	} else {
		err := db.WithContext(ctx).Raw("select sql_calc_found_rows * from t_app  where t_app.id not in (select app_id from t_graph where  t_graph.kind=0 "+query+") and t_app.name like ? limit ?,?", "%"+name+"%", (pageNum-1)*pageSize, pageSize).Scan(&apps).Error
		if err != nil {
			return nil, 0, errors.Wrap(err, "templateRepository.FindUpdateApp error")
		}
		err = db.WithContext(ctx).Raw("SELECT FOUND_ROWS() count").Scan(&count).Error
		if err != nil {
			return nil, 0, errors.Wrap(err, "templateRepository.FindUpdateApp error")
		}
		db.Commit()
		return apps, count, nil
	}
}

func (r templateRepository) FindUpdateApi(ctx context.Context, id uint64, name string, pageNum, pageSize int, eq bool) ([]*models.Api, int64, error) {
	var count int64
	db := r.db.Begin()
	apis := make([]*models.Api, 0)
	query := ""
	if id != 0 {
		query = " and t_graph.template_id=" + strconv.Itoa(int(id))
	}
	if !eq {
		err := db.WithContext(ctx).Raw("select sql_calc_found_rows t_api.* from t_api join t_graph on t_graph.kind=1 "+query+"  and t_graph.api_id=t_api.id and (t_api.http_path like ? or t_api.zeus_method like ? ) limit ?,? ", "%"+name+"%", "%"+name+"%", (pageNum-1)*pageSize, pageSize).Scan(&apis).Error
		if err != nil {
			return nil, 0, errors.Wrap(err, "templateRepository.FindUpdateApi error")
		}
		err = db.WithContext(ctx).Raw("SELECT FOUND_ROWS() count").Scan(&count).Error
		if err != nil {
			return nil, 0, errors.Wrap(err, "templateRepository.FindUpdateApi error")
		}
		db.Commit()
		return apis, count, nil
	} else {
		err := db.WithContext(ctx).Raw("select sql_calc_found_rows t_api.* from t_api  where t_api.id not in (select api_id from t_graph where t_graph.kind=1 "+query+" ) and (t_api.http_path like ? or t_api.zeus_method like ? ) limit ?,?", "%"+name+"%", "%"+name+"%", (pageNum-1)*pageSize, pageSize).Scan(&apis).Error
		if err != nil {
			return nil, 0, errors.Wrap(err, "templateRepository.FindUpdateApi error")
		}
		err = db.WithContext(ctx).Raw("SELECT FOUND_ROWS() count").Scan(&count).Error
		if err != nil {
			return nil, 0, errors.Wrap(err, "templateRepository.FindUpdateApi error")
		}
		db.Commit()
		return apis, count, nil
	}
}

func (r templateRepository) FindUpdateHost(ctx context.Context, id uint64, ip string, pageNum, pageSize int, eq bool) ([]*models.HostResource, int64, error) {
	var count int64
	hosts := make([]*models.HostResource, 0)
	query := ""
	if id != 0 {
		query = " and t_graph.template_id=" + strconv.Itoa(int(id))
	}
	db := r.db.Begin()
	if !eq {
		err := db.WithContext(ctx).Raw("select sql_calc_found_rows t_host.* from t_host join t_graph t_graph.kind=2 "+query+" and t_graph.host_id=t_host.id and t_host.ip like ?  limit ?,?", "%"+ip+"%", (pageNum-1)*pageSize, pageSize).Scan(&hosts).Error
		if err != nil {
			return nil, 0, errors.Wrap(err, "templateRepository.FindUpdateHost error")
		}
		err = db.WithContext(ctx).Raw("SELECT FOUND_ROWS() count").Scan(&count).Error
		if err != nil {
			return nil, 0, errors.Wrap(err, "templateRepository.FindUpdateHost error")
		}
		db.Commit()
		return hosts, count, nil
	} else {
		err := db.WithContext(ctx).Raw("select sql_calc_found_rows t_host.* from t_host  where t_host.id not in (select host_id from t_graph where  t_graph.kind=2 "+query+") and t_host.ip like ?  limit ?,?", "%"+ip+"%", (pageNum-1)*pageSize, pageSize).Scan(&hosts).Error
		if err != nil {
			return nil, 0, errors.Wrap(err, "templateRepository.FindUpdateHost error")
		}
		err = db.WithContext(ctx).Raw("SELECT FOUND_ROWS() count").Scan(&count).Error
		if err != nil {
			return nil, 0, errors.Wrap(err, "templateRepository.FindUpdateHost error")
		}
		db.Commit()
		return hosts, count, nil
	}
}

func (r templateRepository) FindUpdateApps(ctx context.Context, id uint64, eq bool) ([]*models.Application, int64, error) {
	var count int64
	apps := make([]*models.Application, 0)
	db := r.db.Begin()
	query := ""
	if id != 0 {
		query = " and t_graph.template_id=" + strconv.Itoa(int(id))
	}
	if !eq {
		err := db.Begin().WithContext(ctx).Raw("select sql_calc_found_rows * from t_app join t_graph on  t_graph.kind=0 " + query + " and t_graph.app_id=t_app.id ").Scan(&apps).Error
		if err != nil {
			return nil, 0, errors.Wrap(err, "templateRepository.FindUpdateApp error")
		}
		err = db.WithContext(ctx).Raw("SELECT FOUND_ROWS() count").Scan(&count).Error
		if err != nil {
			return nil, 0, errors.Wrap(err, "templateRepository.FindUpdateApp error")
		}
		db.Commit()
		return apps, count, nil
	} else {
		err := db.WithContext(ctx).Raw("select sql_calc_found_rows * from t_app  where t_app.id not in (select app_id from t_graph where  t_graph.kind=0 " + query + ")").Scan(&apps).Error
		if err != nil {
			return nil, 0, errors.Wrap(err, "templateRepository.FindUpdateApp error")
		}
		err = db.WithContext(ctx).Raw("SELECT FOUND_ROWS() count").Scan(&count).Error
		if err != nil {
			return nil, 0, errors.Wrap(err, "templateRepository.FindUpdateApp error")
		}
		db.Commit()
		return apps, count, nil
	}
}

func (r templateRepository) FindUpdateApis(ctx context.Context, id uint64, eq bool) ([]*models.Api, int64, error) {
	var count int64
	db := r.db.Begin()
	apis := make([]*models.Api, 0)
	query := ""
	if id != 0 {
		query = " and t_graph.template_id=" + strconv.Itoa(int(id))
	}
	if !eq {
		err := db.WithContext(ctx).Raw("select sql_calc_found_rows t_api.* from t_api join t_graph on t_graph.kind=1 " + query + "  and t_graph.api_id=t_api.id").Scan(&apis).Error
		if err != nil {
			return nil, 0, errors.Wrap(err, "templateRepository.FindUpdateApi error")
		}
		err = db.WithContext(ctx).Raw("SELECT FOUND_ROWS() count").Scan(&count).Error
		if err != nil {
			return nil, 0, errors.Wrap(err, "templateRepository.FindUpdateApi error")
		}
		db.Commit()
		return apis, count, nil
	} else {
		err := db.WithContext(ctx).Raw("select sql_calc_found_rows t_api.* from t_api  where t_api.id not in (select api_id from t_graph where t_graph.kind=1 " + query + " ) ").Scan(&apis).Error
		if err != nil {
			return nil, 0, errors.Wrap(err, "templateRepository.FindUpdateApi error")
		}
		err = db.WithContext(ctx).Raw("SELECT FOUND_ROWS() count").Scan(&count).Error
		if err != nil {
			return nil, 0, errors.Wrap(err, "templateRepository.FindUpdateApi error")
		}
		db.Commit()
		return apis, count, nil
	}
}

func (r templateRepository) FindUpdateHosts(ctx context.Context, id uint64, eq bool) ([]*models.HostResource, int64, error) {
	var count int64
	hosts := make([]*models.HostResource, 0)
	query := ""
	if id != 0 {
		query = " and t_graph.template_id=" + strconv.Itoa(int(id))
	}
	db := r.db.Begin()
	if !eq {
		err := db.WithContext(ctx).Raw("select sql_calc_found_rows t_host.* from t_host join t_graph t_graph.kind=2 " + query + " and t_graph.host_id=t_host.id ").Scan(&hosts).Error
		if err != nil {
			return nil, 0, errors.Wrap(err, "templateRepository.FindUpdateHost error")
		}
		err = db.WithContext(ctx).Raw("SELECT FOUND_ROWS() count").Scan(&count).Error
		if err != nil {
			return nil, 0, errors.Wrap(err, "templateRepository.FindUpdateHost error")
		}
		db.Commit()
		return hosts, count, nil
	} else {
		err := db.WithContext(ctx).Raw("select sql_calc_found_rows t_host.* from t_host  where t_host.id not in (select host_id from t_graph where  t_graph.kind=2 " + query + ") ").Scan(&hosts).Error
		if err != nil {
			return nil, 0, errors.Wrap(err, "templateRepository.FindUpdateHost error")
		}
		err = db.WithContext(ctx).Raw("SELECT FOUND_ROWS() count").Scan(&count).Error
		if err != nil {
			return nil, 0, errors.Wrap(err, "templateRepository.FindUpdateHost error")
		}
		db.Commit()
		return hosts, count, nil
	}
}
